package com.example.demo.demos.web.Aspect;

import com.example.demo.demos.web.expection.InvalidParameterException;
import com.example.demo.demos.web.util.EmptyUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Aspect
@Component
public class ValidateDtoAspect {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Pointcut("@annotation(com.example.demo.demos.web.Annotation.ValidateDto)")
    public void pointcut() {

    }


    @Before("pointcut()")
    public void before(JoinPoint joinPoint) throws Throwable {
        HttpServletRequest request =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String method = request.getMethod();
        Set<String> keys = null;
        if (HttpMethod.POST.name().equals(method)) {
            // 读取请求体
            StringBuilder jsonBody = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    jsonBody.append(line);
                }
            } catch (IOException e) {
                throw new InvalidParameterException("参数失败");
            }
            //传参的所有属性set集合
            // 将 JSON 转换为 Map
            Map<String, Object> requestMap = null;
            try {
                requestMap = objectMapper.readValue(jsonBody.toString(), Map.class);
            } catch (JsonProcessingException e) {
                // 将 ServletResponse 转换为 HttpServletResponse
                HttpServletResponse response =  ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
                handleJsonError(response,e.getMessage());
            }
            if (EmptyUtil.isBlank(requestMap)) {
                return;
            }
            keys = requestMap.keySet();
        } else if (HttpMethod.GET.name().equals(method)) {
            Map<String, String[]> parameterMap = request.getParameterMap();
            if (EmptyUtil.isBlank(parameterMap)) {
                return;
            }
            keys = parameterMap.keySet();
        }
        //获取切点的方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        log.info("获取到切点方法,{}", methodSignature.getMethod().getName());
        Class[] parameterTypes = methodSignature.getParameterTypes();
        if (parameterTypes != null && parameterTypes.length > 0) {
            Class parameterType = parameterTypes[0];
            log.info("获取到切点的第一个对象,{}", parameterType.getName());
            //获取所有字段
            Field[] declaredFields = parameterType.getDeclaredFields();
            if (declaredFields == null || declaredFields.length == 0) {
                throw new InvalidParameterException("参数错误"); // 传参属性了。但是 dto没有属性值
            }
            //获取dto中所有属性
            Set<String> declaredFieldSet = Arrays.stream(declaredFields).map(Field::getName).collect(Collectors.toSet());
            if (EmptyUtil.isBlank(keys)) {
                return;
            }
            for (String key : keys) {
                if (!declaredFieldSet.contains(key)) {
                    throw new InvalidParameterException("参数错误"); //前端传参不该传的属性 报错
                }
            }
        } else {
            throw new InvalidParameterException("参数错误"); // 后端不存在dto接收时候
        }
    }
        private void handleJsonError(HttpServletResponse response,String msg) {
            try {
                // 设置 HTTP 状态码为 500
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);  // 500 错误状态码
                response.setContentType("application/json; charset=UTF-8");

                // 构造返回的错误消息
                String jsonResponse = String.format("{\"error\": \"%s\"}",msg);

                // 写入响应内容
                PrintWriter writer = response.getWriter();
                writer.write(jsonResponse);
                writer.flush();
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();  // 如果处理错误时发生异常，可以打印错误日志
            }
        }
//        //获取request请求
//        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = attributes.getRequest();
//        //获取 传参属性和值 的map集合
//        Map<String, String[]> parameterMap = request.getParameterMap();
//        log.info(parameterMap.toString());
//        if (parameterMap == null || parameterMap.isEmpty()) {
//            return joinPoint.proceed();
//        }
//        //传参的所有属性set集合
//        Set<String> strings = parameterMap.keySet();
//        //获取切点的方法
//        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//        log.info("获取到切点方法,{}", methodSignature.getMethod().getName());
//        Class[] parameterTypes = methodSignature.getParameterTypes();
//        if (parameterTypes != null && parameterTypes.length > 0) {
//            Class parameterType = parameterTypes[0];
//            log.info("获取到切点的第一个对象,{}", parameterType.getName());
//            //获取所有字段
//            Field[] declaredFields = parameterType.getDeclaredFields();
//            if (declaredFields == null || declaredFields.length == 0) {
//                throw new InvalidParameterException("参数错误"); // 传参属性了。但是 dto没有属性值
//            }
//            //获取dto中所有属性
//            Set<String> declaredFieldSet = Arrays.stream(declaredFields).map(Field::getName).collect(Collectors.toSet());
//            for (String string : strings) {
//                if (!declaredFieldSet.contains(string)) {
//                    throw new InvalidParameterException("参数错误"); //前端传参不该传的属性 报错
//                }
//            }
//        }else {
//            throw new InvalidParameterException("参数错误"); // 后端不存在dto接收时候
//        }

}
